#include "common.h"

#ifndef	SSAO_QUALITY

half	calc_ssao( half3 P, half3 N, half2 tc, half2 tcJ)
{
	return 1.0f;
}

#else	//	SSAO_QUALITY

#if SSAO_QUALITY == 3
#define RINGS 3
#define DIRS 8
const half rads[4] = half[]
( //I know it will be more focused in the cener, but that's OK
    0.20000f,
	0.57735f,
	0.81650f,
	1.00000f
);
const half angles[9] = half[]
(
	0.0000f,
	0.7854f,
	1.5708f,
	2.3562f,
	3.1416f,
	3.9267f,
	4.7124f,
	5.4978f,
	6.2832f
);
#elif SSAO_QUALITY == 2
#define RINGS  3
#define DIRS 4
const half rads[4] = half[]
( //I know it will be more focused in the cener, but that's OK
    0.20000f,
	0.57735f,
	0.81650f,
	1.00000f
);
const half angles[5] = half[]
(
	0.0000f,
	1.5708f,
	3.1416f,
	4.7124f,
	6.2832f
);
#elif SSAO_QUALITY == 1
#define RINGS 2
#define DIRS 4
const half rads[3] = half[]
( //I know it will be more focused in the cener, but that's OK
    0.2000f,
    0.7071f,
	1.0000f,
);
const half angles[5] = half[]
(
	0.0000f,
	1.5708f,
	3.1416f,
	4.7124f,
	6.2832f
);
#endif

uniform float ssao_noise_tile_factor;
uniform float ssao_kernel_size;
uniform float4 pos_decompression_params;

uniform sampler2D 	jitter0;

float3 uv_to_eye(float2 uv, float eye_z)
{
    uv = (uv * float2(2.0, 2.0) - float2(1.0, 1.0));
    return float3(uv * pos_decompression_params.xy * eye_z, eye_z);
}
//	Screen space ambient occlusion
//	P	screen space position of the original point
//	N	screen space normal of the original point
//	tc	G-buffer coordinates of the original point
half	calc_ssao( half3 P, half3 N, half2 tc, half2 tcJ)
{
	half point_depth = P.z;
	if (point_depth<0.01) point_depth = 100000.0f;	//	filter for the sky
//	half2 	scale 	= half2	(.5f / 1024.f, .5f / 768.f)*100/point_depth;
//	half2 	scale 	= half2	(.5f / 1024.f, .5f / 768.f)*100/max(point_depth,1.3);
//	half2 	scale 	= half2	(.5f / 1024.f, .5f / 768.f)*70/point_depth;
//	half2 	scale 	= half2	(.5f / 1024.f, .5f / 768.f)*150/max(point_depth,1.3);
//	Looks better but triggers some strange hardware(?) bug.
	half2 	scale 	= half2	(.5f / 1024.f, .5f / 768.f)*ssao_kernel_size/max(point_depth,1.3);
//	half2 	scale 	= half2	(.5f / 1024.f, .5f / 768.f)*min( ssao_kernel_size/point_depth , ssao_kernel_size/1.3 );

	// sample 
	half 	occ	= 0.1f;	
	half num_dir	= 0.1f;
//	half 	occ	= 1.0f;
//	half num_dir	= 1.0f;

////////////////////////////////
//	jittering

//	half2	Mirror = tex2D( jitter0, tcJ );
//	half2	Mirror = half2(1,1);
	float3 tc1	= mul( m_v2w, float4(P,1) );
	tc1 *= ssao_noise_tile_factor;
//	tc1 *= 2;
//	tc1 *= 4;
	tc1.xz += tc1.y;
	half2	SmallTap = tex2D( jitter0, tc1.xz ).xy;
//	half2	Mirror = tex2D( jitter0, tc1.xz ).xy;
//	Mirror	= normalize(Mirror);

for (int rad=0; rad < RINGS; rad++)
{
	for (int dir=0; dir < DIRS; dir++)
	{
		SmallTap.x += 0.31337f;
		SmallTap.y += 0.73313f;
		SmallTap = frac(SmallTap);
		float	r		= lerp(rads[rad]*1.3, rads[rad+1]*1.3, SmallTap.x);
		float   a		= lerp(angles[dir], angles[dir+1], SmallTap.y);
		float s, c;
		sincos( a, s, c );
		float2	tap = float2( r * c, r * s );
				tap		*= scale;
				tap		+= tc;
#ifndef SSAO_OPT_DATA
		half3	tap_pos	= tex2D	(s_position,tap);
#else // SSAO_OPT_DATA
		float	z	= tex2Dlod(s_half_depth,float4(tap, 0, 0)).x;
		half3	tap_pos	= uv_to_eye(tap, z);
#endif // SSAO_OPT_DATA
		half3 	dir 	= tap_pos-P.xyz;
		half	dist	= length(dir);
			dir 	= normalize(dir);
		half 	infl 	= saturate(dot( dir, N.xyz));
		half 	occ_factor = saturate(dist);

		{
//			occ += lerp( 1, occ_factor, infl);
//			num_dir += 1;		

			occ += (infl+0.01)*lerp( 1, occ_factor, infl)/(occ_factor+0.1);
			num_dir += (infl+0.01)/(occ_factor+0.1);

//			occ += (infl+0.1)*lerp( 1, occ_factor, infl)/(occ_factor+0.1);
//			num_dir += (infl+0.1)/(occ_factor+0.1);

//			occ += (infl+0.1)*lerp( 1, occ_factor, infl);
//			num_dir += (infl+0.1);
		}
	}
}
	occ /= num_dir;

//	occ = lerp(1, occ, saturate(point_depth/1.5f));

	occ = saturate(occ);
//	occ = Contrast(occ,2);
//	occ = occ*1.5 - 0.5;
//	occ = occ*occ;
//	occ = occ*0.5+0.5;
#if SSAO_QUALITY==1
	occ = (occ+0.3)/(1+0.3);
#else	//	SSAO_QUALITY==1
	occ = (occ+0.2)/(1+0.2);
#endif	//	SSAO_QUALITY==1
//	occ = 1;

	float WeaponAttenuation = smoothstep( 0.8, 0.9, length( P.xyz ));
	occ = lerp( 1, occ, WeaponAttenuation );

	return occ;
}

#endif	//	SSAO_QUALITY